export module Utilities {

    export class Dependency<T> {

        private AsyncObservers: Array<AsyncObserver> = new Array<AsyncObserver>();
        private asyncObservable: T = null;

        Resolve() {
            alert("DependencyExecuteNotOverwrittenException");
        }

        // Can be used in 2 ways i.e. as Setter-Method with argument and as Getter-Method without argument
        public AsyncObservable(observable: T = null): T {
            if (observable != null) {
                this.asyncObservable = observable;
                this.Resolved();
                return null;
            }
            if (this.asyncObservable == null) {
                alert("AsyncObservableNotInitializedException");
            }
            return this.asyncObservable;
        }

        Resolved() {
            jQuery.each(this.AsyncObservers, function () {
                if (this.MoveNext()) {
                    this.ResolveCurrent();
                }
            });
        }

        RegisterAsyncObserver(observer: AsyncObserver): void {
            this.AsyncObservers.push(observer);
        }

    }

    // Base class for an application that needs to make a number of inter-dependent 
    // asynchronous calls to a remote server
    export class AsyncObserver {

        private Dependencies: Array<Dependency<any>> = new Array<Dependency<any>>();
        private currPos = -1;

        // Adds a new Dependency object to this AsyncObserver's queue
        public AddDependency(dependency: Dependency<any>): void {
            this.Dependencies.push(dependency);
        }

        // Increments the array index by one and returns true when it's pointing to an existing Dependency 
        public MoveNext(): boolean {
            this.currPos++;
            if (this.Dependencies.length > 0 && (this.Dependencies.length - 1 >= this.currPos)) {
                return true;
            }
            return false;
        }

        // Executes the Resolve method of the current Dependency
        // Usage if(MoveNext()) { ResolveCurrent() }
        public ResolveCurrent(): void {
            if (this.currPos >= 0 && (this.Dependencies.length - 1 >= this.currPos)) {
                this.Dependencies[this.currPos].Resolve();
            } else {
                alert("ArrayIndexOutOfBoundsException");
            }
        }

        public ApplyBinding(dependency: Dependency<any>): void {
            dependency.RegisterAsyncObserver(this);
            this.AddDependency(dependency);
        }
    }
}